﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Telerik.Windows.Documents.Fixed.FormatProviders.Pdf;
using Telerik.Windows.Documents.Fixed.Model;
using Telerik.Windows.Documents.Fixed.Model.ColorSpaces;
using Telerik.Windows.Documents.Fixed.Model.Editing;
using Telerik.Windows.Documents.Fixed.Model.Editing.Flow;
using Telerik.Windows.Documents.Fixed.Model.Editing.Tables;
using Telerik.Windows.Documents.Flow.FormatProviders.Html;
using Telerik.Windows.Documents.Flow.Model;
using Telerik.Windows.Documents.Flow.Model.Shapes;

namespace Console_4._7._2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            RadFlowDocument htmlDocument;
            HtmlFormatProvider htmlFormatProvider = new HtmlFormatProvider();
            HtmlImportSettings importSettings = new HtmlImportSettings();

            importSettings.LoadImageFromUri += (s, e) =>
            {
                // Load the data representing the resource  
                System.Net.WebClient webClient = new System.Net.WebClient();
                byte[] data = webClient.DownloadData(e.Uri);

                // Pass the loaded data to the arguments 
                string extension = System.IO.Path.GetExtension(e.Uri).Substring(1); // Get the extension without the dot 
                e.SetImageInfo(data, extension);
            };

            htmlFormatProvider.ImportSettings = importSettings;

            using (Stream input = File.OpenRead("..\\..\\..\\input.html"))
            {
                htmlDocument = htmlFormatProvider.Import(input, null);
            }

            Telerik.Windows.Documents.Flow.Model.Table htmlTable = htmlDocument.EnumerateChildrenOfType<Telerik.Windows.Documents.Flow.Model.Table>().FirstOrDefault();

            RadFixedDocument pdfDocument = new RadFixedDocument();
            
            // Convert HTML table rows to a list for easier processing
            var htmlRowsList = htmlTable.Rows.ToList();
            int currentRowIndex = 0;

            while (currentRowIndex < htmlRowsList.Count)
            {
                // Create a new page
                RadFixedPage pdfPage = pdfDocument.Pages.AddPage();
                FixedContentEditor pdfPageEditor = new FixedContentEditor(pdfPage);

                // Create a new table for this page
                Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table pdfTable = CreateNewTable(pdfPage);

                // Add rows to the current table until it exceeds page height
                while (currentRowIndex < htmlRowsList.Count)
                {
                    var htmlRow = htmlRowsList[currentRowIndex];
                    
                    // Create and add the row to test if it fits
                    Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableRow pdfRow = CreatePdfRowFromHtmlRow(htmlRow, pdfPage);
                    pdfTable.Rows.AddTableRow(pdfRow);

                    // Measure the table with the new row
                    var currentPdfTableSize = pdfTable.Measure();
                    
                    // Check if table exceeds page height (leaving some margin)
                    if (currentPdfTableSize.Height > pdfPage.Size.Height - 40) // 40 points margin
                    {
                        // Remove the last row that caused overflow
                        pdfTable.Rows.Remove(pdfRow);
                        break; // Start a new page
                    }
                    
                    currentRowIndex++;
                }

                // Draw the table on the current page
                pdfPageEditor.InsertTable(pdfTable);
            }

            PdfFormatProvider pdfProvider = new PdfFormatProvider();
            File.Delete("..\\..\\..\\output.pdf");
            using (Stream output = File.Create("..\\..\\..\\output.pdf"))
            {
                pdfProvider.Export(pdfDocument, output, null);
            }

            var psi = new ProcessStartInfo()
            {
                FileName = "..\\..\\..\\output.pdf",
                UseShellExecute = true
            };
            Process.Start(psi);
        }

        private static Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table CreateNewTable(RadFixedPage pdfPage)
        {
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table pdfTable = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table();
            Border blackBorder = new Border(2, new RgbColor(0, 0, 0));
            pdfTable.DefaultCellProperties.Borders = new TableCellBorders(blackBorder, blackBorder, blackBorder, blackBorder);
            pdfTable.Margin = new System.Windows.Thickness(10, 10, 10, 10);
            return pdfTable;
        }

        private static Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableRow CreatePdfRowFromHtmlRow(
            Telerik.Windows.Documents.Flow.Model.TableRow htmlRow, RadFixedPage pdfPage)
        {
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableRow pdfRow = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableRow();

            foreach (var htmlCell in htmlRow.Cells)
            {
                var pdfCell = pdfRow.Cells.AddTableCell();

                if (htmlRow.Cells.IndexOf(htmlCell) == 0)
                {
                    pdfCell.PreferredWidth = pdfPage.Size.Width * 0.10;
                }
                else if (htmlRow.Cells.IndexOf(htmlCell) == 1)
                {
                    pdfCell.PreferredWidth = pdfPage.Size.Width * 0.80;
                }

                foreach (var htmlBlock in htmlCell.Blocks)
                {
                    var pdfBlock = pdfCell.Blocks.AddBlock();

                    if (htmlBlock is Paragraph htmlParagraph)
                    {
                        foreach (var htmlInline in htmlParagraph.Inlines)
                        {
                            if (htmlInline is ImageInline htmlImageInline)
                            {
                                using (MemoryStream stream = new MemoryStream(htmlImageInline.Image.ImageSource.Data))
                                {
                                    var imageSource = new Telerik.Windows.Documents.Fixed.Model.Resources.ImageSource(stream);
                                    pdfBlock.InsertImage(imageSource);
                                }
                            }
                            else if (htmlInline is Run run)
                            {
                                pdfBlock.InsertText(run.Text);
                            }
                            else if (htmlInline is Break)
                            {
                                pdfBlock.InsertLineBreak();
                            }
                        }
                    }
                }
            }

            return pdfRow;
        }
    }
}
